﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Media;
using AIStudio.Wpf.DiagramDesigner;
using AIStudio.Wpf.DiagramDesigner.Algorithms;
using AIStudio.Wpf.DiagramDesigner.Geometrys;
using AIStudio.Wpf.DiagramDesigner.Helpers;
using AIStudio.Wpf.Mind.ViewModels;

namespace AIStudio.Wpf.Mind.Helpers
{
    public class DirectoryLayout : IMindLayout
    {
        public void Appearance(MindNode mindNode)
        {
            switch (mindNode.NodeLevel)
            {
                case 0:
                    {
                        mindNode.ItemWidth = 110;
                        mindNode.ItemHeight = 40;
                        mindNode.ClearConnectors();

                        var port = new FullyCreatedConnectorInfo(mindNode.Root, mindNode, ConnectorOrientation.Bottom, true) { XRatio = 0.5, YRatio = 1 };
                        mindNode.AddConnector(port);

                        mindNode.IsInnerConnector = true;

                        mindNode.ColorViewModel.FillColor.Color = Color.FromRgb(0x73, 0xa1, 0xbf);
                        mindNode.ColorViewModel.LineColor.Color = Color.FromRgb(0x73, 0xa1, 0xbf);
                        mindNode.FontViewModel.FontColor = Colors.White;
                        mindNode.FontViewModel.FontSize = 15;
                        mindNode.ShapeViewModel.SinkMarker.PathStyle = ArrowPathStyle.None;
                        mindNode.ShapeViewModel.SinkMarker.SizeStyle = ArrowSizeStyle.VerySmall;

                        mindNode.ConnectorOrientation = ConnectorOrientation.None;
                        break;
                    }
                case 1:
                    {
                        mindNode.ItemWidth = 80;
                        mindNode.ItemHeight = 25;
                        mindNode.ClearConnectors();
                        var port1 = new FullyCreatedConnectorInfo(mindNode.Root, mindNode, ConnectorOrientation.Top, true) { XRatio = 0.5, YRatio = 0 };
                        mindNode.AddConnector(port1);
                        var port2 = new FullyCreatedConnectorInfo(mindNode.Root, mindNode, ConnectorOrientation.Bottom, true) { XRatio = 0.25, YRatio = 1 };
                        mindNode.AddConnector(port2);

                        mindNode.IsInnerConnector = true;

                        mindNode.ColorViewModel.LineColor.Color = Color.FromRgb(0x73, 0xa1, 0xbf);
                        mindNode.ShapeViewModel.SinkMarker.PathStyle = ArrowPathStyle.None;
                        mindNode.ShapeViewModel.SinkMarker.SizeStyle = ArrowSizeStyle.VerySmall;
                        break;
                    }
                default:
                    {
                        mindNode.ItemWidth = 80;
                        mindNode.ItemHeight = 25;
                        mindNode.ClearConnectors();

                        var port1 = new FullyCreatedConnectorInfo(mindNode.Root, mindNode, ConnectorOrientation.Left, true) { XRatio = 0, YRatio = 0.5 };
                        mindNode.AddConnector(port1);
                        var port2 = new FullyCreatedConnectorInfo(mindNode.Root, mindNode, ConnectorOrientation.Bottom, true) { XRatio = 0.25, YRatio = 1 };
                        mindNode.AddConnector(port2);

                        mindNode.IsInnerConnector = true;
                        mindNode.ColorViewModel.LineColor.Color = Color.FromRgb(0x73, 0xa1, 0xbf);
                        mindNode.ShapeViewModel.SinkMarker.PathStyle = ArrowPathStyle.None;
                        mindNode.ShapeViewModel.SinkMarker.SizeStyle = ArrowSizeStyle.VerySmall;
                        mindNode.CornerRadius = new System.Windows.CornerRadius(0);
                        mindNode.BorderThickness = new System.Windows.Thickness(0, 0, 0, 0);
                        break;
                    }
            }
        }

        public ConnectionViewModel GetOrSetConnectionViewModel(MindNode source, MindNode sink, ConnectionViewModel connector = null)
        {
            if (connector == null)
            {
                connector = new ConnectionViewModel(source.Root, source.FirstConnector, sink.FirstConnector, DrawMode.ConnectingLineStraight, RouterMode.RouterOrthogonal);
            }
            else
            {
                connector?.SetSourcePort(source.FirstConnector);
                connector?.SetSinkPort(sink.FirstConnector);
                connector.PathMode = DrawMode.ConnectingLineStraight.ToString();
                connector.RouterMode = RouterMode.RouterOrthogonal.ToString();
            }
            connector.ColorViewModel.LineColor = source.ColorViewModel.LineColor;
            connector.SmoothMargin = 20;
            connector.SmoothAutoSlope = 0.2;
            connector.ShapeViewModel.SinkMarker.PathStyle = source.ShapeViewModel.SinkMarker.PathStyle;
            connector.ShapeViewModel.SinkMarker.SizeStyle = source.ShapeViewModel.SinkMarker.SizeStyle;

            return connector;
        }

        public void LayoutUpdated(MindNode mindNode)
        {
            if (mindNode == null) return;

            mindNode.GetLevel1Node().LayoutUpdating = true;
            var size = MeasureOverride(mindNode);
            ArrangeOverride(mindNode);

            mindNode.Root.BringToFrontCommand.Execute(mindNode.Root.Items.OfType<DesignerItemViewModelBase>());

            mindNode.GetLevel1Node().LayoutUpdating = false;
        }


        public SizeBase MeasureOverride(MindNode mindNode, bool isExpanded = true)
        {
            var sizewithSpacing = mindNode.SizeWithSpacing;
            if (mindNode.Children?.Count > 0)
            {
                if (mindNode.NodeLevel == 0)
                {
                    var childrensizes = mindNode.Children.Select(p => MeasureOverride(p, mindNode.IsExpanded && isExpanded)).ToArray();
                    sizewithSpacing = new SizeBase(Math.Max(sizewithSpacing.Width, childrensizes.SumOrDefault(p => p.Width)), sizewithSpacing.Height + childrensizes.MaxOrDefault(p => p.Height));
                }
                else
                {
                    var childrensizes = mindNode.Children.Select(p => MeasureOverride(p, mindNode.IsExpanded && isExpanded)).ToArray();
                    sizewithSpacing = new SizeBase(Math.Max(sizewithSpacing.Width, sizewithSpacing.Width * 0.5 + childrensizes.MaxOrDefault(p => p.Width)), sizewithSpacing.Height + childrensizes.SumOrDefault(p => p.Height));
                }
            }
            mindNode.DesiredSize = isExpanded ? sizewithSpacing : new SizeBase(0, 0);
            mindNode.Visible = isExpanded;

            return mindNode.DesiredSize;
        }

        public void ArrangeOverride(MindNode mindNode)
        {
            if (mindNode.NodeLevel == 0)
            {
                double left = mindNode.MiddlePosition.X - Math.Max(mindNode.DesiredSize.Width, mindNode.Children.SumOrDefault(p => p.DesiredSize.Width)) / 2;
                double top = mindNode.MiddlePosition.Y + mindNode.ItemHeight / 2 + mindNode.Spacing.Height;
                if (mindNode.Children?.Count > 0)
                {
                    foreach (var child in mindNode.Children)
                    {
                        child.Left = left + child.DesiredSize.Width / 2 - child.ItemWidth / 2 + child.Offset.X;
                        child.Top = top + child.Spacing.Height + child.Offset.Y;
                        child.DesiredPosition = child.Position;
                        left += child.DesiredSize.Width;

                        ArrangeOverride(child);

                        var connector = mindNode.Root?.Items.OfType<ConnectionViewModel>().FirstOrDefault(p => p.SourceConnectorInfo?.DataItem == mindNode && p.SinkConnectorInfoFully?.DataItem == child);
                        connector?.SetSourcePort(mindNode.FirstConnector);
                        connector?.SetSinkPort(child.TopConnector);
                        connector?.SetVisible(child.Visible);
                    }
                }
            }
            else
            {
                double left = mindNode.MiddlePosition.X;
                double top = mindNode.MiddlePosition.Y + mindNode.ItemHeight / 2 + mindNode.Spacing.Height;
                if (mindNode.Children?.Count > 0)
                {
                    foreach (var child in mindNode.Children)
                    {
                        child.Left = left + child.Offset.X;
                        child.Top = top + child.Spacing.Height + child.Offset.Y;
                        child.DesiredPosition = child.Position;
                        top += child.DesiredSize.Height;

                        ArrangeOverride(child);

                        var connector = mindNode.Root?.Items.OfType<ConnectionViewModel>().FirstOrDefault(p => p.SourceConnectorInfo?.DataItem == mindNode && p.SinkConnectorInfoFully?.DataItem == child);
                        connector?.SetSourcePort(mindNode.BottomConnector);
                        connector?.SetSinkPort(child.LeftConnector);
                        connector?.SetVisible(child.Visible);
                    }
                }
            }
        }
    }
}
